#include "logic_include/file_download.h"
#include "../include/conf_reader.h"
#include <unistd.h>
#include "../include/my_log.h"
#include <fcntl.h>
#include "../include/global.h"
#include "logic_include/logic_macro.h"

file_downloader* file_downloader::true_file_downloader=nullptr;


file_downloader_thread_item::file_downloader_thread_item(file_downloader * instance_downloader)
{
    this->instance_downloader=instance_downloader;
    pthread_mutex_init(&this->mutex,0);
    pthread_mutex_init(&this->tmp_task_map_mutex,0);
    pthread_cond_init(&this->cond,0);
    //this->is_having_active_item_in_tmp_task_map=false;
    this->is_running=0;
}

//获取
file_downloader_thread_item *file_downloader::get_one_thread_item(int user_id)
{


    return this->downloaders[user_id%this->downloader_num];
}

//构造函数
file_downloader::file_downloader(){
    //从配置文件中读取出下载线程的数量
    this->downloader_num=atoi(conf_reader::get_conf_reader_instance()->get_value_from_key("file_downloader_num","5"));
    this->file_download_flag=FILE_DOWNLOAD_RUNNING;
    for(int i=0;i<downloader_num;++i){
        file_downloader_thread_item *item=new file_downloader_thread_item(this);
        this->downloaders.push_back(item);
        pthread_create(&item->handler,0,file_downloader::thread_func,item);
    }
    //后续这里确保线程开启了
    for(int i=0;i<downloader_num;++i){
        if(downloaders[i]->is_running==0){
            usleep(200*1000);   //睡200ms
            --i;
        }
    }

    my_log::get_log_instance()->write_log(LOG_INFO,0,"成功开启%d个文件下载线程",this->downloader_num);

}




void *file_downloader::thread_func(void *true_file_downloader_thread_item)
{
    file_downloader_thread_item* item=(file_downloader_thread_item*)(true_file_downloader_thread_item);
    std::map<std::pair<connection_p,int>,work_item*>::iterator map_it;  //用于遍历每个work_item
    char buffer[1024];  
    file_download_message send_msg; //存放待发送的数据
    work_item * workItem=nullptr;
    while(1){
      
        pthread_mutex_lock(&item->mutex);
        while(item->task_map.empty()&&item->instance_downloader->file_download_flag==FILE_DOWNLOAD_RUNNING){
            if(!item->is_running){
                item->is_running=true;
            }
            pthread_cond_wait(&item->cond,&item->mutex); 
        }
        
        //解锁，由于进行数据发送并不需要加锁,但是数据的插入会导致数结构变化，如果在遍历过程中，刚好遇到树变化过程，那么会是灾难级的error
        //所以还是得加锁
        //pthread_mutex_unlock(&item->mutex);
        
        //醒来，判断是否结束----只有在程序结束才会退出
        if(item->instance_downloader->file_download_flag==FILE_DOWNLOAD_END){
            pthread_mutex_unlock(&item->mutex);
            break;
        }

        //遍历每一个work_item,进行一个发送，对每一个file_item里的数据进行1次的发送
        
        map_it=item->task_map.begin();
        
        while(map_it!=item->task_map.end()){
            workItem=map_it->second;
            //先判断当前连接有无失效，失效了那就不必进行发送了
            if(workItem->con_p->icurrentsequence!=workItem->icurrentsequence){
                //那么将这个任务移除,也要回收资源
                delete map_it->second;
                map_it=item->task_map.erase(map_it);
                continue;
            }
            //否则进行一个发送逻辑处理

            // 1.拿取到workItem中头部file_item节点-----这里能确保begin一定能有数据？
            auto file_item_it=workItem->work_item_map.begin();

            if(file_item_it->second->opened_fd==-1){
                file_item_it->second->opened_fd=open(file_item_it->second->file_servername.c_str(),O_RDONLY);
                if(file_item_it->second->opened_fd==-1){
                    //如果文件继续打不开，那么日志记录一下
                    my_log::get_log_instance()->write_log(LOG_ERR,errno,"在发送文件的线程中，无法打开文件%s进行数据发送！！",file_item_it->second->file_servername.c_str());
                    ++map_it;
                    continue;   //说不定下一个已经被正确打开，可以接着发送
                }
                //这里进行文件指针的偏移,后续就不必进行偏移了，毕竟顺序读取发送即可
                lseek(file_item_it->second->opened_fd,file_item_it->second->transformed_size,SEEK_SET);
            }
            //2.进行数据读取,并填充send_msg
            

            int read_res=read(file_item_it->second->opened_fd,buffer,1024);

            send_msg.set_seq(file_item_it->second->seq);
            send_msg.set_data(buffer,read_res);
            send_msg.set_file_path_name(file_item_it->first);
            send_msg.set_offset((file_item_it->second->seq)*1024);
            send_msg.set_work_id(workItem->work_id);
            
            //3.进行数据发送
            std::string need_send_str;
            send_msg.SerializeToString(&need_send_str);
            //将数据放入发送缓冲区中
            work_socket.move_message_to_send_list(workItem->con_p,need_send_str.c_str(),need_send_str.length(),FILE_DOWNLOAD);

            //4. 简单的收尾工作
            file_item_it->second->transformed_size+=read_res;
            file_item_it->second->seq++;
            if(file_item_it->second->transformed_size==file_item_it->second->file_size){
                //说明发送完毕，移除即可，还要delete对应的数据
                my_log::get_log_instance()->write_log(LOG_INFO,0,"成功发送完毕一个任务中的一个文件");
                close(file_item_it->second->opened_fd);
                file_item_it->second->opened_fd=-1;
                delete file_item_it->second;
                workItem->work_item_map.erase(file_item_it);
                if(workItem->work_item_map.empty()){
                    //如果该任务没有需要发送的东西了，那么就移除该workItem
                    delete map_it->second;
                    map_it=item->task_map.erase(map_it);
                    std::cout<<"成功发送完一个任务，并且释放内存"<<std::endl;
                    continue;
                }
            }

            ++map_it;   //如果没有涉及task_map数据的删除，那么就要++，进行后续遍历
        }


        pthread_mutex_unlock(&item->mutex);

        

    }
    

    return NULL;
}



//一系列的析构函数

void file_downloader::end_downloader()
{
    this->file_download_flag=FILE_DOWNLOAD_END;
    for(int i=0;i<this->downloader_num;++i){
       
        delete downloaders[i];
    }
}

file_downloader::~file_downloader()
{
    this->end_downloader();
}

//具体每个线程句柄的析构函数
file_downloader_thread_item::~file_downloader_thread_item()
{
    //唤醒后，等待结束
    pthread_cond_broadcast(&this->cond);
    pthread_join(this->handler,NULL);

    pthread_mutex_destroy(&this->mutex);
    pthread_mutex_destroy(&this->tmp_task_map_mutex);
    pthread_cond_destroy(&this->cond);
    //好像也不需要这里去回收map里的资源
    if(!this->task_map.empty()){
        my_log::get_log_instance()->write_log(LOG_INFO,0,"怎么要~file_downloader_thread_item去回收map里的资源");
        auto it=this->task_map.begin();
        while(it!=this->task_map.end()){
            delete it->second;
        }
    }

    if(!this->tmp_task_map.empty()){
        my_log::get_log_instance()->write_log(LOG_INFO,0,"怎么要~file_downloader_thread_item去回收tmp_map里的资源");
        auto it=this->tmp_task_map.begin();
        while(it!=this->tmp_task_map.end()){
            delete it->second;
        }
    }
}

//每个线程体里的子任务的析构函数
work_item::~work_item()
{
    auto it=work_item_map.begin();
    while(it!=work_item_map.end()){
        if(it->second->opened_fd!=-1){
            close(it->second->opened_fd);
            it->second->opened_fd=-1;
        }
        delete it->second;
    }

}